package algo3.grupo3.controlador;

import java.io.File;
import java.util.Iterator;
import java.util.LinkedList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import algo3.grupo3.modelo.AreaCasillas;
import algo3.grupo3.modelo.Articulo;
import algo3.grupo3.modelo.ArticuloToleTole;
import algo3.grupo3.modelo.BloqueAcero;
import algo3.grupo3.modelo.BloqueConArticulo;
import algo3.grupo3.modelo.Bomba;
import algo3.grupo3.modelo.Bombita;
import algo3.grupo3.modelo.Chala;
import algo3.grupo3.modelo.Enemigo;
import algo3.grupo3.modelo.Salida;
import algo3.grupo3.modelo.Timer;
import algo3.grupo3.vista.EntidadBloqueAcero;
import algo3.grupo3.vista.EntidadBloqueConArticulo;
import algo3.grupo3.vista.EntidadBomba;
import algo3.grupo3.vista.EntidadEnemigo;

public class ManejadorMemoria {

	private LogicaJuego logicaJuego= null;
	private AreaCasillas areaCasillas;
	
	public ManejadorMemoria(LogicaJuego lj){
		this.establecerLogicaJuego(lj);
	}//fin de constructor
	
	public void establecerLogicaJuego(LogicaJuego lj){
		if(lj== null)
			return;
		this.logicaJuego= lj;
	}//fin de establecerLogicaJuego
	
	public void guardarDatos(String pathArchivo){
		
		
		DocumentBuilderFactory dbf= DocumentBuilderFactory.newInstance();
		DocumentBuilder db= null;
		Document d= null;
		
		try{
			db= dbf.newDocumentBuilder();
			d= db.newDocument();
		}catch(Exception e){}
		
		//CREACION RAIZ PRINCIPAL -----------------------------------------------
		
		//elemento raiz principal del documento es creada
		Element raiz= d.createElement("Escenario");
		d.appendChild(raiz);
		
		this.guardarBloquesConArticulo(d);
		this.guardarBloquesAcero(d);
		this.guardarBombas(d);
		this.guardarEnemigos(d);
		this.guardarBombita(d);
		this.guardarNivel(d);
		this.guardarPuntos(d);
		this.guardarSalida(d);
		
		//INICIO GUARDADO DATOS EN ARCHIVO-----------------------------------------------------
		
		Source source = new DOMSource(d);
		Result result = new StreamResult(new java.io.File(pathArchivo)); //nombre del archivo
		
		Transformer transformer= null;
		
		try{
			transformer = TransformerFactory.newInstance().newTransformer();
			transformer.transform(source, result);
		}catch(Exception e){}
		
	}//fin de guardarDatos
	
	

	private void guardarSalida(Document d) {
		if(this.logicaJuego.obtenerSalida()== null)
			return;
		Salida s= (Salida)this.logicaJuego.obtenerSalida().obtenerObjeto();
		int posicionSalida[]= s.obtenerCoordenadas();
		if(posicionSalida== null)
			return;
		
		Element nodo= d.createElement("BloqueConArticulo");
		nodo.setAttribute("posicionX", ""+posicionSalida[0]);
		nodo.setAttribute("posicionY", ""+posicionSalida[1]);
		nodo.setAttribute("durabilidad", ""+BloqueConArticulo.DURABILIDAD_BLOQUE_CEMENTO);
		nodo.setAttribute("articuloContenido", ""+Articulo.SALIDA);
		d.getDocumentElement().appendChild(nodo);
		
	}//fin de guardarSalida

	private void guardarPuntos(Document d) {

		Element raiz= d.getDocumentElement();
		raiz.setAttribute("puntos", ""+this.logicaJuego.obtenerPuntos());
		
	}//fin de guardarPuntos

	private void guardarBloquesConArticulo(Document d){
		
		LinkedList<EntidadBloqueConArticulo> lista= 
			this.logicaJuego.obtenerListaBloquesConArticulo();
		Iterator<EntidadBloqueConArticulo> iterador= lista.iterator(); 
		EntidadBloqueConArticulo entidad;
		BloqueConArticulo bca;
		Articulo a;
		Element nodo;
		
		while(iterador.hasNext()){
			entidad= iterador.next();
			nodo= d.createElement("BloqueConArticulo");
			nodo.setAttribute("posicionX", ""+entidad.obtenerObjeto().obtenerCoordenadas()[0]);
			nodo.setAttribute("posicionY", ""+entidad.obtenerObjeto().obtenerCoordenadas()[1]);
			nodo.setAttribute("durabilidad", ""+entidad.obtenerObjeto().obtenerDurabilidad());
			bca= (BloqueConArticulo)entidad.obtenerObjeto();
			a= bca.obtenerArticulo();
			if(a!= null)
				nodo.setAttribute("articuloContenido", ""+a.obtenerTipoDeArticulo());
			else
				nodo.setAttribute("articuloContenido", ""+0);
			d.getDocumentElement().appendChild(nodo);
		}
		
		
	}//fin de guardarBloquesConArticulo
	
	private void guardarBloquesAcero(Document d){
		
		LinkedList<EntidadBloqueAcero> lista= 
			this.logicaJuego.obtenerListaBloquesAcero();
		Iterator<EntidadBloqueAcero> iterador= lista.iterator(); 
		EntidadBloqueAcero entidad;
		Element nodo;
		
		while(iterador.hasNext()){
			entidad= iterador.next();
			nodo= d.createElement("BloqueAcero");
			nodo.setAttribute("posicionX", ""+entidad.obtenerObjeto().obtenerCoordenadas()[0]);
			nodo.setAttribute("posicionY", ""+entidad.obtenerObjeto().obtenerCoordenadas()[1]);
			d.getDocumentElement().appendChild(nodo);
		}
		
	}//fin de guardarBloquesAcero
	
	
	private void guardarBombas(Document d){
		
		LinkedList<EntidadBomba> lista= 
			this.logicaJuego.obtenerListaBombas();
		Iterator<EntidadBomba> iterador= lista.iterator(); 
		EntidadBomba entidad;
		Element nodo;
		Bomba bomba;
		
		while(iterador.hasNext()){
			entidad= iterador.next();
			nodo= d.createElement("Bomba");
			nodo.setAttribute("posicionX", ""+entidad.obtenerObjeto().obtenerCoordenadas()[0]);
			nodo.setAttribute("posicionY", ""+entidad.obtenerObjeto().obtenerCoordenadas()[1]);
			bomba= (Bomba)entidad.obtenerObjeto();
			nodo.setAttribute("tipo", ""+bomba.obtenerTipo());
			
			d.getDocumentElement().appendChild(nodo);
		}
		
	}//fin de guardarBombas
	
	private void guardarEnemigos(Document d){
		
		LinkedList<EntidadEnemigo> lista= 
			this.logicaJuego.obtenerListaEnemigos();
		Iterator<EntidadEnemigo> iterador= lista.iterator(); 
		EntidadEnemigo entidad;
		Element nodo;
		Enemigo enemigo;
		
		while(iterador.hasNext()){
			entidad= iterador.next();
			enemigo= (Enemigo) entidad.obtenerObjeto();
			nodo= d.createElement("Enemigo");
			nodo.setAttribute("posicionX", ""+enemigo.obtenerCoordenadas()[0]);
			nodo.setAttribute("posicionY", ""+enemigo.obtenerCoordenadas()[1]);
			nodo.setAttribute("tipo",""+enemigo.obtenerTipoEnemigo());
			nodo.setAttribute("durabilidad", ""+enemigo.obtenerDurabilidad());
			
			d.getDocumentElement().appendChild(nodo);
		}
		
	}//fin de guardarEnemigos
	
	
	private void guardarBombita(Document d){
		
		if(logicaJuego.obtenerEntidadBombita()== null)
			return;
		Bombita bombita= (Bombita)this.logicaJuego.obtenerEntidadBombita().obtenerObjeto();
		if(bombita== null)
			return;
		Element nodo= d.createElement("Bombita");
		nodo.setAttribute("posicionX", ""+bombita.obtenerCoordenadas()[0]);
		nodo.setAttribute("posicionY", ""+bombita.obtenerCoordenadas()[1]);
		nodo.setAttribute("delayMovimiento", ""+bombita.obtenerDelayMovimiento());
		nodo.setAttribute("tipoBomba", ""+bombita.obtenerBomba().obtenerTipo());
		
		d.getDocumentElement().appendChild(nodo);
		
	}//fin de guardarBombita
	
	
	private void guardarNivel(Document d){
		Element raiz= d.getDocumentElement();
		raiz.setAttribute("nivel", ""+this.logicaJuego.obtenerNivelActual());
	}//fin de guardarNivel
	
	
	public void cargarDatos(String pathArchivo){
		
		DocumentBuilderFactory dbf= DocumentBuilderFactory.newInstance();
		DocumentBuilder db= null;
		Document d= null;
		
		try{
			db= dbf.newDocumentBuilder();
			d= db.parse(new File(pathArchivo));
		}catch(Exception e){}
		
		this.crearAreaCasillas();	
		//this.areaCasillas= new AreaCasillas(9,9);
		
		this.vaciarListas();
		this.cargarBloquesAcero(d);
		this.cargarBloquesConArticulo(d);
		this.cargarEnemigos(d);
		this.cargarBombas(d);
		this.cargarNivel(d);
		this.cargarBombita(d);
		this.cargarPuntos(d);
		
	}//fin de cargarDatos
	
	

	private void cargarPuntos(Document d) {
		Element raiz= d.getDocumentElement();
		NamedNodeMap nnm= raiz.getAttributes();
		Node nodoAtributoPuntos= nnm.getNamedItem("puntos");
		if(nodoAtributoPuntos== null)
			return;
		String atributoPuntos= nodoAtributoPuntos.getNodeValue();
		int puntos= Integer.parseInt(atributoPuntos);
		this.logicaJuego.establecerPuntos(puntos);
		
	}

	private void crearAreaCasillas(){
		
		int alto,ancho;
		if(this.logicaJuego.obtenerVentanaJuego()== null){
			alto=ancho=10;
		}else{
			alto= this.logicaJuego.obtenerVentanaJuego().obtenerAltoMapa();
			ancho= this.logicaJuego.obtenerVentanaJuego().obtenerAnchoMapa();
		}
		
		this.areaCasillas= new AreaCasillas(alto-1,ancho-1);
		
	}//fin de crearAreaCasillas
	
	private void vaciarListas(){
		
		this.logicaJuego.vaciarListaBloquesAcero();
		this.logicaJuego.vaciarListaBloquesConArticulo();
		this.logicaJuego.vaciarListaEnemigos();
		this.logicaJuego.vaciarListaBombas();
		this.logicaJuego.removerBombita();
		this.logicaJuego.vaciarListaChalas();
		this.logicaJuego.vaciarListaTimers();
		this.logicaJuego.vaciarListaToleToles();
		this.logicaJuego.removerSalida();
		
		
	}//fin de vaciarListas
	
	private void cargarBloquesAcero(Document d){
		
		Element raiz= d.getDocumentElement();
		NodeList listaNodosBloquesAcero= raiz.getElementsByTagName("BloqueAcero");
		Node nodo;
		NamedNodeMap atributos;
		Node atributo;
		int posicionX;
		int posicionY;
		

		BloqueAcero bloqueNuevo;
		
		for(int i=0; i<listaNodosBloquesAcero.getLength();i++){
			
			nodo= listaNodosBloquesAcero.item(i);
			atributos= nodo.getAttributes();
			atributo= atributos.getNamedItem("posicionX");
			posicionX= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("posicionY");
			posicionY= Integer.parseInt(atributo.getNodeValue());
			
			bloqueNuevo= new BloqueAcero();
			this.areaCasillas.obtenerCasillaEn(posicionX, posicionY).compartir(bloqueNuevo);
			this.logicaJuego.agregarBloqueAcero(bloqueNuevo);
			
		}		
		
	}//fin de cargarBloquesAcero
	
	
	private void cargarBloquesConArticulo(Document d){
		
		Element raiz= d.getDocumentElement();
		NodeList listaNodosBloquesConArticulo= raiz.getElementsByTagName("BloqueConArticulo");
		Node nodo;
		NamedNodeMap atributos;
		Node atributo;
		int posicionX;
		int posicionY;
		int durabilidad;
		int articuloContenido= 0;
		
		BloqueConArticulo bloqueNuevo;
		
		for(int i=0; i<listaNodosBloquesConArticulo.getLength();i++){
			
			nodo= listaNodosBloquesConArticulo.item(i);
			atributos= nodo.getAttributes();
			atributo= atributos.getNamedItem("posicionX");
			posicionX= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("posicionY");
			posicionY= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("durabilidad");
			durabilidad= Integer.parseInt(atributo.getNodeValue());
			atributo = atributos.getNamedItem("articuloContenido");
			if(atributo!=null)
				articuloContenido = Integer.parseInt(atributo.getNodeValue());
			
			bloqueNuevo= new BloqueConArticulo();
			bloqueNuevo.setearDurabilidad(durabilidad);
			
			
			switch (articuloContenido) {
			case Articulo.CHALA:
				Chala unaChala = new Chala();
				bloqueNuevo.agregarArticulo(unaChala);
				break;
				
			case Articulo.TIMER:
				Timer unTimer = new Timer();
				bloqueNuevo.agregarArticulo(unTimer);
				break;
				
			case Articulo.TOLETOLE:
				ArticuloToleTole unaToleTole = new ArticuloToleTole();
				bloqueNuevo.agregarArticulo(unaToleTole);
				break;

			case Articulo.SALIDA:
				Salida unaSalida = new Salida(this.areaCasillas);
				bloqueNuevo.agregarArticulo(unaSalida);
				break;
			}
			
			this.areaCasillas.obtenerCasillaEn(posicionX, posicionY).compartir(bloqueNuevo);
			this.logicaJuego.agregarBloqueConArticulo(bloqueNuevo);
			
		}		
		
	}//fin de cargarBloquesArticulo
	
	
	private void cargarEnemigos(Document d){
		
		Element raiz= d.getDocumentElement();
		NodeList listaNodosEnemigos= raiz.getElementsByTagName("Enemigo");
		Node nodo;
		NamedNodeMap atributos;
		Node atributo;
		int posicionX;
		int posicionY;
		int durabilidad;
		int tipo;
		
		Enemigo enemigoNuevo;
		
		for(int i=0; i<listaNodosEnemigos.getLength();i++){
			
			nodo= listaNodosEnemigos.item(i);
			atributos= nodo.getAttributes();
			atributo= atributos.getNamedItem("posicionX");
			posicionX= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("posicionY");
			posicionY= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("durabilidad");
			durabilidad= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("tipo");
			tipo= Integer.parseInt(atributo.getNodeValue());
			
			enemigoNuevo= new Enemigo();
			switch(tipo){
			case Enemigo.CECILIO:
				enemigoNuevo.convertirACecilio();
				break;
			case Enemigo.LOPEZ_REGGAE:
				enemigoNuevo.convertirALopezReggae();
				break;
			case Enemigo.LOPEZ_REGGAE_ALADO:
				enemigoNuevo.convertirALopezReggaeAlado();
				break;
			default:
				enemigoNuevo.convertirALopezReggae();
				break;
			}//fin del switch
			
			enemigoNuevo.cambiarDurabilidad(durabilidad);
			this.areaCasillas.agregarEnemigo(enemigoNuevo);
			this.areaCasillas.obtenerCasillaEn(posicionX, posicionY).ocupar(enemigoNuevo);
			this.logicaJuego.agregarEnemigo(enemigoNuevo);
			
		}
		
	}//fin de cargarEnemigos
	
	private void cargarBombas(Document d){
		
		Element raiz= d.getDocumentElement();
		NodeList listaNodosBombas= raiz.getElementsByTagName("Bomba");
		Node nodo;
		NamedNodeMap atributos;
		Node atributo;
		int posicionX;
		int posicionY;
		int tipo;
		
		Bomba bombaNueva;
		
		for(int i=0; i<listaNodosBombas.getLength();i++){
			
			nodo= listaNodosBombas.item(i);
			atributos= nodo.getAttributes();
			atributo= atributos.getNamedItem("posicionX");
			posicionX= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("posicionY");
			posicionY= Integer.parseInt(atributo.getNodeValue());
			atributo= atributos.getNamedItem("tipo");
			tipo= Integer.parseInt(atributo.getNodeValue());
			
			bombaNueva= new Bomba();
			switch(tipo){
			case Bomba.MOLOTOV:
				bombaNueva.convertirAMolotov();
				break;
			case Bomba.TOLE_TOLE:
				bombaNueva.convertirAToleTole();
				break;
			case Bomba.MEDIA_BOMBA:
				bombaNueva.convertirAMediaBomba();
				break;
			case Bomba.ENEMIGO:
				bombaNueva.convertirABombaEnemigo();
				break;
			default:
				bombaNueva.convertirAMolotov();
				break;
			}//fin del switch
			
			this.areaCasillas.obtenerCasillaEn(posicionX, posicionY).compartir(bombaNueva);
			this.logicaJuego.agregarBomba(bombaNueva);
			
		}
		
	}//fin de cargarBombas
	
	
	private void cargarNivel(Document d){
		Element raiz= d.getDocumentElement();
		NamedNodeMap nnm= raiz.getAttributes();
		Node nodoAtributoNivel= nnm.getNamedItem("nivel");
		String atributoNivel= nodoAtributoNivel.getNodeValue();
		if(atributoNivel== null ){
			this.logicaJuego.establecerNivelActual(1);
			return;
		}
		if(atributoNivel== ""){
			this.logicaJuego.establecerNivelActual(1);
			return;
		}
		int nivelActual= Integer.parseInt( raiz.getAttribute("nivel") );
		this.logicaJuego.establecerNivelActual(nivelActual);
		
	}//fin de cargarNivel
	
	
	private void cargarBombita(Document d){
		
		Element raiz= d.getDocumentElement();
		Node nodoBombita= raiz.getElementsByTagName("Bombita").item(0);
		NamedNodeMap atributos= nodoBombita.getAttributes();
		Node atributo;
		int posicionX,posicionY,tipoBomba;
		double delayMovimiento;
		
		atributo= atributos.getNamedItem("posicionX");
		posicionX= Integer.parseInt(atributo.getNodeValue());
		atributo= atributos.getNamedItem("posicionY");
		posicionY= Integer.parseInt(atributo.getNodeValue());
		atributo= atributos.getNamedItem("delayMovimiento");
		delayMovimiento= Double.parseDouble(atributo.getNodeValue());
		atributo= atributos.getNamedItem("tipoBomba");
		tipoBomba= Integer.parseInt(atributo.getNodeValue());
		
		Bombita bombita= new Bombita();
		switch(tipoBomba){
		case Bomba.MOLOTOV:
			bombita.obtenerBomba().convertirAMolotov();
			break;
		case Bomba.TOLE_TOLE:
			bombita.obtenerBomba().convertirAToleTole();
			break;
		case Bomba.MEDIA_BOMBA:
			bombita.obtenerBomba().convertirAMediaBomba();
			break;
		default:
			bombita.obtenerBomba().convertirAMolotov();
			break;
		}
		bombita.setearDelayMovimiento(delayMovimiento);
		this.areaCasillas.obtenerCasillaEn(posicionX, posicionY).ocupar(bombita);
		this.logicaJuego.agregarJugador(bombita);
		
	}//fin de cargarBombita
	
}//fin de ManipuladorMemoria
